#include "my_i2c.h"

void I2C_GPIO_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = I2C_SDA_Pin | I2C_SCL_Pin;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(I2C_PORT, &GPIO_InitStructure);

    I2C_SDA_H;
    I2C_SCL_H;
}

void I2C_SDA_OUT(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = I2C_SDA_Pin;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(I2C_PORT, &GPIO_InitStructure);
}

void I2C_SDA_IN(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStructure.GPIO_Pin = I2C_SDA_Pin;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(I2C_PORT, &GPIO_InitStructure);
}

uint8_t I2C_SDA_Read(void)
{
    return ((GPIOB->IDR & I2C_SDA_Pin)!=0) ? 1 : 0;
}

void I2C_Start(void)
{
    I2C_SDA_OUT();//SDA口输出
    //两线先全部拉高
    I2C_SDA_H;
    I2C_SCL_H;
    delay_us(4);
    //先拉高SDA
    I2C_SDA_L;
    delay_us(4);
    I2C_SCL_L;
}

void I2C_Stop(void)
{
    I2C_SDA_OUT();//SDA输出
    I2C_SCL_L;
    I2C_SDA_L;
    delay_us(4);
    I2C_SCL_H;
    I2C_SDA_H;
    delay_us(4);
}
/**
 * @brief uint8_t I2C_Wait_Ack(void)
 *        等待应答信号到来 从机第9个信号SCL = 0时 SDA被拉低
 *        并且SCL = 1时 SDA依然为低
 * @param:None
 * @return:return 1:应答失败
 *         return 0:应答成功
 * @note:从机给主机的应答
 */
uint8_t I2C_WaitAck(void)
{
    uint8_t Rx_ErrTime = 0;
    I2C_SDA_IN(); //从机给一个低电平做为应答信号
    I2C_SDA_H;
    delay_us(1);
    I2C_SCL_H;
    delay_us(1);
    while (I2C_SDA_Read())
    {
        Rx_ErrTime++;
        if (Rx_ErrTime > 250)
        {//应答超时 
            I2C_Stop();
            return 1;
        }
    }
    //接收应答信号成功
    I2C_SCL_L;
    return 0;   
}

/**
 * @brief 主机 发送 应答信号
 * 
 */
void I2C_Send_Ack_Mater(void)
{
    I2C_SCL_L;
    I2C_SDA_OUT();
    I2C_SDA_L;
    delay_us(2);
    I2C_SCL_H;
    delay_us(2);
    I2C_SCL_L;
}

/**
 * @brief 主机发送 不接收应答 的信号
 * 
 */
void I2C_Send_NAck_Mater(void)
{
    I2C_SCL_L;
    I2C_SDA_OUT();
    I2C_SDA_H;
    delay_us(2);
    I2C_SCL_H;
    delay_us(2);
    I2C_SCL_L;
}

//写一个字节数据
void I2C_SendByte(uint8_t data)
{
    uint8_t pos = 0;
    I2C_SDA_OUT();
    I2C_SCL_L;//拉低时钟开始数据传输
    for (pos = 0; pos < 8; pos++)
    {
        if (data & 0x80)
            I2C_SDA_H;
        else
            I2C_SDA_L;
        data <<= 1;
        delay_us(2);
        I2C_SCL_H;
        delay_us(2);
        I2C_SCL_L;
        delay_us(2);
    }
}

uint8_t I2C_ReadByte(uint8_t ack)
{
    uint8_t pos, receive = 0;
    I2C_SDA_IN();
    for (pos = 0; pos < 8; pos ++)
    {
        I2C_SCL_L;
        delay_us(2);
        I2C_SDA_H;
        receive <<= 1;
        if (I2C_SDA_Read()) receive ++;
        delay_us(2);
    }
    if (ack)
        I2C_Send_Ack_Mater();
    else I2C_Send_NAck_Mater();
    return receive;
}

/**
 * @brief 读取指定从设备指定寄存器的一个值
 * 
 * @param I2C_Addr 目标设备地址
 * @param reg 目标寄存器地址
 * @return uint8_t 1:失败  0:成功
 */
uint8_t I2C_ReadByteFromSlave(uint8_t I2C_Addr, uint8_t reg,uint8_t *buf)
{
	I2C_Start();	
	I2C_SendByte(I2C_Addr);	 //发送从机地址
	if(I2C_WaitAck()) //如果从机未应答则数据发送失败
	{
		I2C_Stop();
		return 1;
	}
	I2C_SendByte(reg); //发送寄存器地址
	I2C_WaitAck();	  
	
	I2C_Start();
	I2C_SendByte(I2C_Addr+1); //进入接收模式			   
	I2C_WaitAck();
	*buf=I2C_ReadByte(0);	   
	I2C_Stop(); //产生一个停止条件
	return 0;
}

/**
 * @brief 写入指定从设备指定寄存器的一个值
 * 
 * @param I2C_Addr 目标设备地址
 * @param reg 目标寄存器地址
 * @param buf 读取数据要存储的地址
 * @return uint8_t 
 */
uint8_t I2C_WriteByteToSlave(uint8_t I2C_Addr, uint8_t reg, uint8_t data)
{
    I2C_Start();
    I2C_SendByte(I2C_Addr);
    if (I2C_WaitAck())
    {
        I2C_Stop();
        return 1;
    }
    I2C_SendByte(reg);
    I2C_WaitAck();
    I2C_SendByte(data);
    if (I2C_WaitAck())
    {
        I2C_Stop();
        return 1;
    }
    I2C_Stop();
    return 0;
}

/**
 * @brief 读取某个从设备的length个数据
 * 
 * @param dev 指定从设备的地址
 * @param reg 指定从设备的寄存器
 * @param length 要读的字节数
 * @param data 读出的数据放入指针内
 * @return uint8_t ：0: 成功 1: 失败
 */
uint8_t I2C_ReadMultByteFromSlave(uint8_t dev, uint8_t reg, uint8_t length, uint8_t *data)
{
    uint8_t count = 0;
    uint8_t temp;
    I2C_Start();
    I2C_SendByte(dev);
    if (I2C_WaitAck())
    {
        I2C_Stop();
        return 1;
    }
    I2C_SendByte(reg);
    I2C_WaitAck();
    I2C_Start();
    I2C_SendByte(dev | 1); //进入接收模式
    I2C_WaitAck();
    for (count = 0; count < length; count ++)
    {
        if (count != (length - 1))
            temp = I2C_ReadByte(1);
        else          
            temp = I2C_ReadByte(0);
        data[count] = temp;
    }
    I2C_Stop(); //产生一个停止条件，方便下一个时序进行
    return 0;
}

/**
 * @brief 写入某个从设备的length个数据
 * 
 * @param dev 从设备的地址
 * @param reg 从设备的某个寄存器    
 * @param length 要写入的长度
 * @param data 写入的数据的指针
 * @return uint8_t 1：失败  0：成功
 */
uint8_t I2C_WriteMultByteToSalve(uint8_t dev, uint8_t reg, uint8_t length, uint8_t *data)
{
    uint8_t count = 0;
    I2C_Start();
    I2C_SendByte(dev);
    if (I2C_WaitAck())
    {
        I2C_Stop();
        return 1;
    }
    I2C_SendByte(reg);
    I2C_WaitAck();
    for (count = 0; count < length; count ++)
    {
        I2C_SendByte(data[count]);
        if (I2C_WaitAck())
        {
            I2C_Stop();
            return 1;
        }
    }
    I2C_Stop(); //产生一个停止条件，方便下一个时序进行
    return 0;
}
